﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Pancliente.Soporte;
using Pancliente.Transferencia;
using System.IO;
using System.Diagnostics;
using System.ServiceModel;

namespace Pancliente
{
    public class AdminCliente
    {
        private SoporteService _soporteCliente;
        private TransferenciaService _transferenciaCliente;
        private int _id;

        public ConfiguracionCliente Configuracion { get; set; }

        public AdminCliente(ConfiguracionCliente configuracion)
        {
            Configuracion = configuracion;
            GenerarID();
            ConfigurarClientes();
        }

        private void GenerarID()
        {
            Random ran = new Random();
            _id = ran.Next(1, int.MaxValue);
        }

        private void ConfigurarClientes()
        {
            try
            {
                BasicHttpBinding basicBinding = new BasicHttpBinding();
                EndpointAddress endpoint = new EndpointAddress(Configuracion.SoporteURL);
                ChannelFactory<SoporteService> channel = new ChannelFactory<SoporteService>(basicBinding, endpoint);
                _soporteCliente = channel.CreateChannel();
                
                BasicHttpBinding basicMTOMBinding = new BasicHttpBinding();
                basicMTOMBinding.MessageEncoding = WSMessageEncoding.Mtom;
                basicBinding.TransferMode = TransferMode.Streamed;
                basicMTOMBinding.CloseTimeout = new TimeSpan(00, 05, 00);
                basicMTOMBinding.OpenTimeout = new TimeSpan(00, 05, 00);
                basicMTOMBinding.ReceiveTimeout = new TimeSpan(00, 05, 00);
                basicMTOMBinding.SendTimeout = new TimeSpan(00, 05, 00);
                basicMTOMBinding.MaxReceivedMessageSize = int.MaxValue;
                basicMTOMBinding.MaxBufferSize = int.MaxValue;

                EndpointAddress endpointTransferencia = new EndpointAddress(Configuracion.TransferenciaURL);
                ChannelFactory<TransferenciaService> channelTransferencia = new ChannelFactory<TransferenciaService>(basicMTOMBinding, endpointTransferencia);
                _transferenciaCliente = channelTransferencia.CreateChannel();
            }
            catch (Exception ex)
            {
                GuardarErrores(ex);
            }
        }

        public void GuardarErrores(Exception ex)
        {
            if (Configuracion.ArchivoErrores == null || !Environment.CurrentDirectory.ToLower().Equals(Configuracion.CarpetaInstalacion.ToLower()))
                return;

            string path = AppDomain.CurrentDomain.BaseDirectory + @"\" + Configuracion.ArchivoErrores;

            using (StreamWriter writer = new StreamWriter(path))
            {
                writer.WriteLine();
                writer.WriteLine("-----------------------------------------------------------"); ;
                writer.WriteLine("ERROR - " + DateTime.Now.ToString()); ;
                writer.WriteLine("Mensaje: " + ex.Message);
                writer.WriteLine("Stacktrace:");
                writer.WriteLine(ex.StackTrace);
                writer.WriteLine("-----------------------------------------------------------"); ;
            }
        }


        public void BuscarComando()
        {
            try
            {
                Comando comando = _soporteCliente.ObtenerComando(Configuracion.Alias, Environment.MachineName, _id);
                ProcesarComando(comando);
            }
            catch (Exception ex)
            {
                GuardarErrores(ex);
            }
        }

        private void ProcesarComando(Comando comando)
        {
            switch (comando.Tipo)
            {
                case TipoComando.SinAccion:
                    break;

                case TipoComando.SolicitarDrives:
                    MostrarDrives(comando);
                    break;

                case TipoComando.Explorar:
                    Explorar(comando);
                    break;

                case TipoComando.Ejecutar:
                    Ejecutar(comando);
                    break;

                case TipoComando.Eliminar:
                    Eliminar(comando);
                    break;

                case TipoComando.Copiar:
                    Copiar(comando);
                    break;

                case TipoComando.Subir:
                    Subir(comando);
                    break;

                case TipoComando.Descargar:
                    Descargar(comando);
                    break;

                case TipoComando.Informar:
                    InformarElemento(comando);
                    break;

                default:
                    break;
            }
        }

        private void MostrarDrives(Comando comando)
        {
            ResultadoComando resultado = new ResultadoComando();
            resultado.Comando = comando;

            try
            {
                if (comando.Path == null)
                    resultado.Carpetas = Directory.GetLogicalDrives().ToArray();
            }
            catch (Exception ex)
            {
                resultado.Error = ex.Message;
            }

            _soporteCliente.EnviarResultado(resultado);
        }

        private void Explorar(Comando comando)
        {
            ResultadoComando resultado = new ResultadoComando();
            resultado.Comando = comando;

            try
            {
                DirectoryInfo dir = new DirectoryInfo(comando.Path);
                resultado.Carpetas = dir.GetDirectories().Select(d => d.Name).ToArray();
                resultado.Archivos = dir.GetFiles().Select(f => f.Name).ToArray();
            }
            catch (Exception ex)
            {
                resultado.Error = ex.Message;
            }

            _soporteCliente.EnviarResultado(resultado);
        }

        private void Ejecutar(Comando comando)
        {
            ResultadoComando resultado = new ResultadoComando();
            resultado.Comando = comando;

            try
            {
                string[] array = comando.Path.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
                ProcessStartInfo info = new ProcessStartInfo(array[0]);

                if (array.Length > 1)
                    info.Arguments = array[1];

                Process.Start(info);
            }
            catch (Exception ex)
            {
                resultado.Error = ex.Message;
            }

            _soporteCliente.EnviarResultado(resultado);
        }

        private void Eliminar(Comando comando)
        {
            ResultadoComando resultado = new ResultadoComando();
            resultado.Comando = comando;

            try
            {
                if (File.Exists(comando.Path))
                    File.Delete(comando.Path);

                if (Directory.Exists(comando.Path))
                    Directory.Delete(comando.Path);
            }
            catch (Exception ex)
            {
                resultado.Error = ex.Message;
            }

            _soporteCliente.EnviarResultado(resultado);
        }

        private void Copiar(Comando comando)
        {
            ResultadoComando resultado = new ResultadoComando();
            resultado.Comando = comando;

            try
            {
                string[] array = comando.Path.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
                string archivoOrigen = array[0];
                string carpetaDestino = array[1];

                array = archivoOrigen.Split(new string[] { @"\" }, StringSplitOptions.RemoveEmptyEntries);
                string archivoDestino = carpetaDestino + @"\" + array[array.Length - 1];

                File.Copy(archivoOrigen, archivoDestino);
            }
            catch (Exception ex)
            {
                resultado.Error = ex.Message;
            }

            _soporteCliente.EnviarResultado(resultado);
        }

        private void Subir(Comando comando)
        {
            ResultadoComando resultado = new ResultadoComando();
            resultado.Comando = comando;

            try
            {
                string[] array = comando.Path.Split(new string[] { @"\" }, StringSplitOptions.RemoveEmptyEntries);
                string nombreArchivo = array[array.Length - 1];

                SolicitudArchivo solicitud = new SolicitudArchivo();
                solicitud.NombreFichero = nombreArchivo;
                Archivo archivo = _transferenciaCliente.Descargar(solicitud);

                int leidos = 0;
                int lenght = 2048;
                byte[] buffer = new byte[lenght];

                using (FileStream writer = new FileStream(comando.Path, FileMode.CreateNew, FileAccess.Write))
                    do
                    {
                        leidos = archivo.Bytes.Read(buffer, 0, lenght);
                        writer.Write(buffer, 0, leidos);
                    } while (leidos != 0);
            }
            catch (Exception ex)
            {
                resultado.Error = ex.Message;
            }

            _soporteCliente.EnviarResultado(resultado);
        }

        private void Descargar(Comando comando)
        {
            ResultadoComando resultado = new ResultadoComando();
            resultado.Comando = comando;

            try
            {
                FileInfo info = new FileInfo(comando.Path);
                FileStream stream = new FileStream(comando.Path, FileMode.Open, FileAccess.Read);

                Archivo archivo = new Archivo();
                archivo.NombreFichero = info.Name;
                archivo.Bytes = stream;
                ResultadoEnvioArchivo envio = _transferenciaCliente.Subir(archivo);

                if (envio.Error != null && envio.Error.Length > 0)
                    throw new Exception(envio.Error);
            }
            catch (Exception ex)
            {
                resultado.Error = ex.Message;
            }

            _soporteCliente.EnviarResultado(resultado);
        }

        private void InformarElemento(Comando comando)
        {
            ResultadoComando resultado = new ResultadoComando();
            resultado.Comando = comando;

            try
            {
                if (File.Exists(comando.Path))
                {
                    FileInfo info = new FileInfo(comando.Path);
                    resultado.Bytes = info.Length;
                }
                else if (Directory.Exists(comando.Path))
                {
                    DirectoryInfo info = new DirectoryInfo(comando.Path);
                    resultado.CantidadArchivos = info.GetFiles().Length;
                    resultado.CantidadSubCarpeta = info.GetDirectories().Length;
                }
            }
            catch (Exception ex)
            {
                resultado.Error = ex.Message;
            }

            _soporteCliente.EnviarResultado(resultado);
        }
    }
}
